package com.gitee.l0km.xthrift.thrift.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.concurrent.TimeUnit;

import com.gitee.l0km.aocache.annotations.AoCacheable;
import com.gitee.l0km.com4j.basex.reflection.FieldUtils;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * @author guyadong
 * @since 1.5.0
 */
public class FieldSupport {
	@AoCacheable(maximumSize = 100, expireAfterAccess = 20, expireAfterAccessTimeUnit = TimeUnit.SECONDS)
	private static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException {
		Field field = FieldUtils.getField(clazz, fieldName, true);
		if (null == field) {
			throw new NoSuchFieldException(String.format("No Such Field '%s' in %s", fieldName, clazz.getName()));
		}
		return field;
	}
	/**
	 * 反射方式获取{@code obj}中 {@code fieldName} 指定字段的值
	 * @param <T>
	 * @param obj
	 * @param fieldName
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fieldValueOf(Object obj, String fieldName) {
		try {
			Field field = getField(checkNotNull(obj,"obj is null").getClass(), fieldName);
			field.setAccessible(true);
			return (T) field.get(obj);
		} catch (IllegalAccessException | NoSuchFieldException e) {
			throw new RuntimeException(e);
		}
	}
	public static void setValueOfField(Object obj, String fieldName,Object value) {
		try {
			Field field = getField(checkNotNull(obj,"obj is null").getClass(), fieldName);
			field.setAccessible(true);
			field.set(obj,value);
		} catch (IllegalAccessException | NoSuchFieldException e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 反射方式获取{@code clazz}指定类型中{@code fieldName}指定静态字段的值
	 * @param <T>
	 * @param clazz
	 * @param fieldName
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fieldValueOf(Class<?> clazz, String fieldName) {
		try {
			Field field = getField(clazz, fieldName);
			checkArgument(Modifier.isStatic(field.getModifiers()),"%s.%s not static field",clazz,fieldName);
			field.setAccessible(true);
			return (T) field.get(null);
		} catch (IllegalAccessException | NoSuchFieldException e) {
			throw new RuntimeException(e);
		}
	}
	public static void setValueOfField(Class<?> clazz, String fieldName,Object value) {
		try {
			Field field = getField(checkNotNull(clazz,"obj is null"), fieldName);
			checkArgument(Modifier.isStatic(field.getModifiers()),"%s.%s not static field",clazz,fieldName);
			field.setAccessible(true);
			field.set(null,value);
		} catch (IllegalAccessException | NoSuchFieldException e) {
			throw new RuntimeException(e);
		}
	}

}
